namespace Org.Loon.Framework.Xna.Game.Action.Sprite {
	
    using Org.Loon.Framework.Xna.Game.Core.Graphics.OpenGL;
    using Org.Loon.Framework.Xna.Game.Core.Graphics;
    using Org.Loon.Framework.Xna.Java.Collections;
    using Org.Loon.Framework.Xna.Game.Core.Geom;
    using Org.Loon.Framework.Xna.Game.Core;
    using Org.Loon.Framework.Xna.Game.Action.Sprite;
    using Org.Loon.Framework.Xna.Game.Utils;
    using System.Collections.Generic;
	
	public class Node : LObject, ISprite {

        public sealed class NodeComparer : IComparer<Node>
        {
			public int Compare(Node one, Node two) {
				return one.zIndex - two.zIndex;
			}
		}

        private IComparer<Node> zIndexComparator = new NodeComparer();
	
		protected internal int width, height;
	
		protected internal LTexture texture;
	
		private LColor color = new LColor(LColor.white);
	
		protected internal List<Node> children = new List<Node>();
	
		private List<Node> requireRemove = new List<Node>();
	
		private int zIndex = 0;
	
		protected internal Node parent = null;
	
		private bool visible = true;

        public Node(string fileName)
            : this(LTextures.LoadTexture(fileName), 0, 0)
        {
			
		}
	
		public Node(string fileName, float x, float y):	this(LTextures.LoadTexture(fileName), x, y) {
		
		}
	
		public Node(LTexture tex2d, float x, float y) {
			this.texture = tex2d;
			this.SetLocation(x, y);
			this.width = tex2d.GetWidth();
			this.height = tex2d.GetHeight();
		}
	
		public Node(string fileName, float x, float y,
				float w, float h) :			this(LTextures.LoadTexture(fileName), x, y, w, h){

		}
	
		public Node(LTexture tex2d, float x, float y,
				float w, float h) {
			this.texture = tex2d;
			this.SetLocation(x, y);
			this.width = (int) w;
			this.height = (int) h;
		}
	
		public Node GetParent() {
			return parent;
		}
	
		public void SetSize(float w, float h) {
			this.width = (int) w;
			this.height = (int) h;
		}

        public override void Update(long elapsedTime)
        {
			int remove = requireRemove.Count;
			if (remove > 0) {
				for (int index = 0; index < remove; index++) {
					Node removedChild = requireRemove[index];
					children.Remove(removedChild);
				}
				requireRemove.Clear();
			}
            Node[] nodes = children.ToArray();
            System.Array.Sort(nodes, zIndexComparator);
            int size = nodes.Length;
			for (int j = 0; j < size; j++) {
                Node child = nodes[j];
				child.Update(elapsedTime);
			}
		}

        public override int GetWidth()
        {
			return width;
		}

        public override int GetHeight()
        {
			return height;
		}
	
		public void SetColor(LColor c) {
			color.SetColor(c);
		}
	
		public LColor GetColor() {
			return color;
		}
	
		public override float GetAlpha() {
			return color.a;
		}

        public override void SetAlpha(float a)
        {
            color.a = a;
        }
	
		public void SetVisible(bool v) {
			this.visible = v;
		}
	
		public bool IsVisible() {
			return visible;
		}
	
		public void CreateUI(GLEx g) {
			if (!visible) {
				return;
			}
			if (texture != null) {
                g.DrawTexture(texture, location.x, location.y, width, height, rotation,color);
			}
			Paint(g, location.x, location.y);
			int size = children.Count;
			if (size == 0) {
				return;
			}
			for (int index = 0; index < size; index++) {
				Node child = children[index];
				if (child.visible) {
					float pX = location.x + child.location.x;
					float pY = location.y + child.location.y;
                    g.DrawTexture(child.texture, pX, pY, child.width, child.height,
                            child.rotation, child.color);
					Paint(g, pX, pY);
				}
			}
		}
	
		public virtual void Paint(GLEx g, float x, float y) {
	
		}
       
		public void AddChild(Node child, int z) {
			child.zIndex = z;
			child.parent = this;
            Node[] nodes = children.ToArray();
            int index = System.Array.BinarySearch(nodes, child, zIndexComparator);
            if (index >= 0)
            {
                int size = nodes.Length;
                Node prevChild;
                do
                {
                    prevChild = nodes[index];
                    index++;
                } while (index < size
                        && nodes[index].zIndex == prevChild.zIndex);
            }
            else
            {
                index = -(index + 1);
            }
            children.Insert(index, child);
		}
	
		public void AddChild(Node pChild) {
			AddChild(pChild, pChild.zIndex);
		}
	
		public void ReorderZIndex(Node pChild, int pZIndex) {
			children.Remove(pChild);
			AddChild(pChild, pZIndex);
		}
	
		public void RemoveChild(Node pChild) {
			pChild.parent = null;
			requireRemove.Add(pChild);
		}
	
		public IList<Node> GetChildren() {
			return this.children;
		}
	
		public int GetZIndex() {
			return this.zIndex;
		}
	
		public RectBox GetCollisionBox() {
			return GetRect(X(), Y(), width, height);
		}
	
		public LTexture GetBitmap() {
			return texture;
		}
	
		public void Dispose() {
			this.visible = false;
			if (texture != null) {
				texture.Destroy();
				texture = null;
			}
		}
	}
}
